/**
  ******************************************************************************
  * @file    xxx.c 
  * @author  SD Electronics xxx
  * @version V1.0
  * @date    xx-xx-xx
  * @brief   xxxxxxxxxxxxxxxxxx.
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "sd_common.h"


/** 
  * @brief  Function Declaration
  */
static void app_mesh_recv_gen_onoff_led_msg(mesh_model_msg_ind_t const *ind);
static void app_mesh_recv_vendor_msg(mesh_model_msg_ind_t const *ind);

/** 
  * @brief  出厂名字
  */
uint8_t MeshFactoryName[27] = "SD Mesh";

/** 
  * @brief  Mesh_composition_cfg_t
  */ 
mesh_composition_cfg_t dev_cfg = {
    .features = MESH_FEATURE_RELAY | MESH_FEATURE_PROXY | MESH_FEATURE_PB_GATT,
    .cid = 0x08b4, //公司的名称
    .vid = 0x000f,
    .pid = 0x0006,
};

/** 
  * @brief  SIG mesh配网定时器
  */
static os_timer_t sig_mesh_prov_timer;  


/** 
  * @brief  app_mesh_user_adv_list---未知结构体？
  */ 
static struct co_list app_mesh_user_adv_list;

/** 
  * @brief  Mesh Key else 
  */ 
uint8_t mesh_key_bdaddr[] = {0xda,0xbb,0x6b,0x07,0xda,0x71};
uint8_t mesh_key_pid[] = {0x0e, 0x01, 0x00, 0x00};
uint8_t mesh_key_secret[] = {0x92,0x37,0x41,0x48,0xb5,0x24,0xd9,0xcf,0x7c,0x24,0x04,0x36,0x0b,0xa8,0x91,0xd0};

/** 
  * @brief  Mesh 硬件配置相关结构体 
  */ 
ST_Mesh_PHY g_stMeshPhyParam = {
    NULL,
    NULL,
    false,
};

/** 
  * @brief Mesh 控制结构体 
  */ 
ST_Mesh_CTRL g_stMeshCtrl = 
{                       
    false,
    &g_stMeshPhyParam,
};

/** 
  * @brief  Mesh model define
  */ 
static mesh_model_t light_models[] = 
{
    [0] = {
        .model_id = MESH_MODEL_ID_ONOFF,
        .model_vendor = MODEL_TYPE_SIG,
        .element_idx = 0,
        .msg_handler = app_mesh_recv_gen_onoff_led_msg,
    },
    [1] = {
        .model_id = MESH_MODEL_ID_VENDOR_DATA,
        .model_vendor = MODEL_TYPE_VENDOR,
        .element_idx = 0,
        .msg_handler = app_mesh_recv_vendor_msg,
    },
};

/**
  * @}
  */

/*********************************************************************
 * @fn      app_mesh_recv_gen_onoff_led_msg
 *
 * @brief   used to check new received message whether belongs to generic on-off
 *          model or not.
 *
 * @param   ind     - message received from remote node
 *
 * @return  None.
 */
static void app_mesh_recv_gen_onoff_led_msg(mesh_model_msg_ind_t const *ind)
{
    
    if(ind->model_id == MESH_MODEL_ID_ONOFF && ind->opcode == MESH_GEN_ONOFF_SET_UNACK)
    {
        printf("[app_mesh_recv_gen_onoff_led_msg]\r\n");
        co_printf("[model_id: 0x%04X]\r\n", ind->model_id);
        co_printf("[opcode: 0x%08X]\r\n", ind->opcode);
            
        co_printf("[msg: ");
        for(uint8_t i=0; i<ind->msg_len; i++)
        {
            co_printf("%02x ", ind->msg[i]);
        }
        co_printf("]\r\n");
        /* 执行GPIO的控制--开灯关灯 */
    }
}

/*********************************************************************
 * @fn      app_mesh_recv_gen_onoff_led_msg
 *
 * @brief   used to check new received message whether belongs to lightness
 *          model or not.
 *
 * @param   ind     - message received from remote node
 *
 * @return  None.
 */
static void app_mesh_recv_vendor_msg(mesh_model_msg_ind_t const *ind)
{   
    if(ind->model_id == MESH_MODEL_ID_VENDOR_DATA && ind->opcode == 0x001F00D3)
    {
        uint8_t trans_data[64];
        uint8_t temp_data[64];
        #if 1
        printf("[app_mesh_recv_vendor_msg]\r\n");
        /* 这个数据如果是组内发送过来的，那么会包含
        *其他Mod的数据，需要根据opcode做下区分和解析 */
        co_printf("[model_id: 0x%04X]\r\n", ind->model_id);
        co_printf("[opcode: 0x%08X]\r\n", ind->opcode);
        co_printf("[SRC: %08X]\r\n", ind->src);
        co_printf("[msg: ");
        for(uint8_t i = 0; i < ind->msg_len; i ++)
        {
            co_printf("%02x ", ind->msg[i]);
        }
        co_printf("]\r\n");
        #endif
        /* HEX转字符串 */
        hex_arr_to_str(ind->msg, ind->msg_len, temp_data);
        sprintf((char *)trans_data,"+MDATA=%s\r\n", temp_data);
        co_printf("[app-uart]:%d, %s\r\n", strlen((char *)trans_data), (char *)trans_data);
        /* 接收到Vendor Modle的消息执行串口发送 */
        SDDevManageCtrl(EN_DEV_USART, 0, strlen((char *)trans_data), (char *)trans_data);
    }
}

/**
  * @brief  mesh_callback_func
  * @note   mesh message deal callback function.
  * @param  None
  * @retval None
  */
static void mesh_callback_func(mesh_event_t * event)
{
    uint8_t tmp_data[16];
    if(event->type != MESH_EVT_ADV_REPORT) 
        co_printf("[mesh_callback_func: %02X]\r\n", event->type);

    switch(event->type) {
        /* Ready mesh 事件 */
        case MESH_EVT_READY:
            mesh_start();
            break;
         /* 启动mesh 事件 */
        case MESH_EVT_STARTED:
            /* 如果已经入网 */
            if(g_stMeshCtrl.pstMeshInfo->MeshInNetWork)
                mesh_proxy_ctrl(1);/* 使能可连接 */
            break;
        /* mesh停止 事件 */
        case MESH_EVT_STOPPED:

            break;
        case MESH_EVT_PROXY_CTRL_STATUS:
            co_printf("[MESH_EVT_PROXY_CTRL_STATUS: status is 0x%04x]\r\n", event->param.proxy_adv_status);
            break;
         /* 已经入网 */
        case MESH_EVT_IN_NETWORK:
            co_printf("[device already in network]\r\n");
            /* 设置入网状态为 true */
            g_stMeshCtrl.pstMeshInfo->MeshInNetWork = true;
            break;
        /* provisioner 操作删除节点事件 */
        case MESH_EVT_RESET:
            g_stMeshCtrl.pstMeshInfo->MeshInNetWork = false;
            co_printf("[removed from network by provisoner]\r\n");
            /* 清除网络信息 */
            mesh_info_clear();

#ifdef MESH_USER_DATA_STORE
            /* 清除mesh用户数据 */
            app_mesh_user_data_clear();
#endif
            /* 手动重启 */
            platform_reset_patch(0);
            break;
        
        /* 配网参数响应 */   
        case MESH_EVT_PROV_PARAM_REQ:
            co_printf("[MESH_EVT_PROV_PARAM_REQ: ");
            tmp_data[0] = 0xa8;
            tmp_data[1] = 0x01;
            tmp_data[2] = 0x71;
            memcpy(&tmp_data[3], mesh_key_pid, 4);
            memcpy(&tmp_data[7], mesh_key_bdaddr, 6);
#if ALI_SIG_MESH_VERSION == 1
            tmp_data[13] = 0x02;
#else   // SIG_MESH_VERSION == 1
            tmp_data[13] = 0x00;
#endif  // SIG_MESH_VERSION == 1
            tmp_data[14] = 0x00;
            tmp_data[15] = 0x00;
            /* 发送配网参数 */
            mesh_send_prov_param_rsp((uint8_t *)tmp_data, 0xd97478b3, 0, 0, 0, 0, 0, 0, 0, 1, 0);
            show_reg(tmp_data, 16, 1);
            co_printf("]\r\n");
            break;
        
        /* 配网权限数据响应 */
        case MESH_EVT_PROV_AUTH_DATA_REQ:
            co_printf("[MESH_EVT_PROV_AUTH_DATA_REQ]\r\n");
            sha256_gen_auth_value((BYTE *)mesh_key_pid, (BYTE *)mesh_key_bdaddr, (BYTE *)mesh_key_secret, tmp_data);
            mesh_send_prov_auth_data_rsp(true, 16, (uint8_t *)tmp_data);
            break;

        /* 配网结果 */
        case MESH_EVT_PROV_RESULT:
            co_printf("result=%d\r\n",event->param.prov_result.state);
            if(event->param.prov_result.state == 1) {
                os_timer_start(&sig_mesh_prov_timer, 30000, false);
            }
            break;
        /* 参数更新 */
        case MESH_EVT_UPDATE_IND:
            co_printf("[UPD TYPE = %02X]\r\n", event->param.update_ind->upd_type);
            /* APP Key更新 */
            if(event->param.update_ind->upd_type == MESH_UPD_TYPE_APP_KEY_UPDATED)
            {
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                co_printf("[APP_KEY: ");
                for(uint16_t i=2; i<(2+16); i++) {
                    co_printf("%02x", data[length-i-1]);
                }
                co_printf("]\r\n");
            }
            /* Net KEY */
            else if(event->param.update_ind->upd_type == MESH_UPD_TYPE_NET_KEY_UPDATED)
            {
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                co_printf("[NETWORK_KEY: ");
                for(uint16_t i=0; i<(0+16); i++) {
                    co_printf("%02x", data[length-i-1]);
                }
                co_printf("]\r\n");
            }
            /* 状态更新 */
            else if(event->param.update_ind->upd_type == MESH_UPD_TYPE_STATE)
            {
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                if(data[1] == 7/*M_TB_STORE_TYPE_DEV_KEY*/) {
                    co_printf("[DEV_KEY: ");
                    for(uint16_t i=2; i<(2+16); i++) {
                        co_printf("%02x", data[length-i-1]);
                    }
                    co_printf("]\r\n");
                }
            }
            /* Publish 参数 */
            else if(event->param.update_ind->upd_type == MESH_UPD_TYPE_PUBLI_PARAM)
            {
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                co_printf("[PUBLISH PARAM: ");
                for(uint16_t i=0; i<length; i++) {
                    co_printf("%02x", data[length-i-1]);
                }
                co_printf("]\r\n");
            }

            /* sublist 参数 */
            else if(event->param.update_ind->upd_type == MESH_UPD_TYPE_SUBS_LIST)
            {
                /* 停止配网定时器 */
                os_timer_stop(&sig_mesh_prov_timer);
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                co_printf("[SUBSCRIPT LIST: ");
                for(uint16_t i=0; i<length; i++) {
                    co_printf("%02x", data[length-i-1]);
                }
                co_printf("]\r\n");
                /* 解析SRC、组地址等 */

            }
            /* Bind参数更新 */
            else if(event->param.update_ind->upd_type == MESH_UPD_TYPE_BINDING)
            {
                uint16_t length = event->param.update_ind->length;
                uint8_t *data = event->param.update_ind->data;
                /* 停止配网定时器 */
                os_timer_stop(&sig_mesh_prov_timer);
                co_printf("[BINDING: ");
                for(uint16_t i=0; i<length; i++) {
                    co_printf("%02x", data[length-i-1]);
                }
                co_printf("]\r\n");
            }
#if ALI_SIG_MESH_VERSION == 1
            if(event->param.update_ind->upd_type == MESH_UPD_TYPE_APP_KEY_UPDATED) // message type is app key update
            {
                mesh_appkey_t *appkey = (mesh_appkey_t *)event->param.update_ind->data;
                app_key_binding_id = appkey->appkey_id;
                mesh_model_bind_appkey(light_models[app_key_binding_count].model_id,
                                      light_models[app_key_binding_count].element_idx,
                                      app_key_binding_id);
                app_key_binding_count++;
            }
#endif  //SIG_MESH_VERSION == 1
            /* 保存信息 */
            app_mesh_store_info_timer_start(2000);
            break;

        /* Mesh接收到消息 */
        case MESH_EVT_RECV_MSG:
        {
            mesh_model_msg_ind_t *ind = &(event->param.model_msg);
            #if 0/* 调试打印MSG */
            co_printf("[model_id: 0x%04X]\r\n", ind->model_id);
            co_printf("[opcode: 0x%08X]\r\n", ind->opcode);
            co_printf("[src: %08X]\r\n", ind->src);
            co_printf("[dst: %08X]\r\n", ind->dst);
            co_printf("[msg: ");
            for(uint8_t i=0; i<ind->msg_len; i++)
            {
                co_printf("%02x ", ind->msg[i]);
            }
            co_printf("]\r\n");
            #endif
            #if 1
            for(uint8_t i = 0; i < sizeof(light_models)/sizeof(light_models[0]); i++)
            {
                /* 执行相关回调 */
                if((ind->element == light_models[i].element_idx) && (ind->model_id == light_models[i].model_id))
                {
                    light_models[i].msg_handler(ind);
                    break;
                }
            }
            #endif
        }
        break;
        /* 广播扫描 */
        case MESH_EVT_ADV_REPORT:
        {
            #if 0
            gap_evt_adv_report_t *report = &(event->param.adv_report);
            co_printf("recv adv from: %02x-%02x-%02x-%02x-%02x-%02x\r\n", report->src_addr.addr.addr[5],
                                                                            report->src_addr.addr.addr[4],
                                                                            report->src_addr.addr.addr[3],
                                                                            report->src_addr.addr.addr[2],
                                                                            report->src_addr.addr.addr[1],
                                                                            report->src_addr.addr.addr[0]);
            for(uint16_t i=0; i<report->length; i++) {
                co_printf("%02x ", report->data[i]);
            }
            co_printf("\r\n");
            #endif
        }
        break;

        /* 停止代理广播 */
        case MESH_EVT_PROXY_END_IND:
            co_printf("[MESH_EVT_PROXY_END_IND]\r\n");
            mesh_proxy_ctrl(1);
            break;
        
        /* 销毁 error is detected */
        case MESH_EVT_FATAL_ERROR:
            co_printf("[MESH_EVT_FATAL_ERROR]\r\n");
            platform_reset_patch(0);
            break;
        default:
            break;
    }
}


/**
  * @brief  sig_mesh_prov_timer_handler
  * @note   xxx
  * @param  None
  * @retval None
  */
static void sig_mesh_prov_timer_handler(void *arg)
{
    #if 0
    mesh_info_clear();
    #ifdef MESH_USER_DATA_STORE
    app_mesh_user_data_clear();
    #endif
    platform_reset_patch(0);
    #endif
}

/**
  * @brief  SDInitMesh
  * @note   xxx
  * @param  None
  * @retval None
  */
void SDInitMesh(PST_Mesh_PHY pstMeshCntPhy)
{
    /***************************************************设置扫描回应包***********************************************/
    uint8_t *rsp_pos;
    uint8_t scan_rsp_data[0x1F];
    uint8_t scan_rsp_data_len = 0;
    uint8_t local_name_len = 0;
    if(pstMeshCntPhy->MeshName != NULL)
        local_name_len = strlen((char *)pstMeshCntPhy->MeshName);
    else
        local_name_len = strlen((char *)MeshFactoryName);
    rsp_pos = &scan_rsp_data[0];
    *rsp_pos++ = local_name_len + 1;                            //pos len;(payload + type)
    *rsp_pos++  = GAP_ADVTYPE_LOCAL_NAME_COMPLETE;              //pos: type
    memcpy(rsp_pos, MeshFactoryName, local_name_len);
    rsp_pos += local_name_len;
    scan_rsp_data_len = ((uint32_t)rsp_pos - (uint32_t)(&scan_rsp_data[0]));
    mesh_set_scan_rsp_data(scan_rsp_data_len, scan_rsp_data);
    //printf("[%s][%d]\r\n", scan_rsp_data, local_name_len);

    /* co list init */
    co_list_init(&app_mesh_user_adv_list);

    /* 修改Mesh的MAC地址 */
    mac_addr_t set_addr;
    gap_address_get(&set_addr);
    memcpy(mesh_key_bdaddr, set_addr.addr, 6);
    mesh_key_bdaddr[0] += 1; //to distinguish the mesh address and general gatt address

    /* Mesh事件回调函数 */
    mesh_set_cb_func(mesh_callback_func);

    /* register several models */
    for(uint8_t i = 0; i < sizeof(light_models)/sizeof(light_models[0]); i ++){
        mesh_add_model(&light_models[i]);
    }

    /* user to start mesh stack initialization */
    mesh_init(dev_cfg, (void *)mesh_key_bdaddr, MESH_INFO_STORE_ADDR);
    app_mesh_store_info_timer_init();
    os_timer_init(&sig_mesh_prov_timer, sig_mesh_prov_timer_handler, NULL);
    printf("[sd Mesh init]\r\n");
}

/**
  * @brief  MeshOpen
  * @note   xxx
  * @param  None
  * @retval None
  */
static long MeshOpen(void *pvHandle, unsigned long ulOption)
{
    PST_DEV_MANAGE pstDevManage = pvHandle;

    long lRet = EN_DEV_CTL_RET_CODE_FAILED;
    if (0 != pstDevManage)
    {
        PST_Mesh_CTRL pstMeshCtrl = (PST_Mesh_CTRL)pstDevManage->pvData;
        if(false == pstMeshCtrl->bInitFlag)
        {
			/* Mesh */
            SDInitMesh(pstMeshCtrl->pstMeshInfo);
            pstMeshCtrl->bInitFlag = true;
        }
        lRet = EN_DEV_CTL_RET_CODE_SUCCESSED;
    }
    return lRet;
}  

/**
  * @brief  MeshRead
  * @note   xxx
  * @param  None
  * @retval None
  */
static long MeshRead(void *pvHandle, unsigned long ulOpertion, unsigned char *pucDataBuf, int* ulDataSize)
{
    PST_DEV_MANAGE pstDevManage = pvHandle;
    long lRet = EN_DEV_CTL_RET_CODE_FAILED;
    if (0 != pstDevManage)
    {
        PST_Mesh_CTRL pstMeshCtrl = (PST_Mesh_CTRL)pstDevManage->pvData;
        //
        if(true == pstMeshCtrl->bInitFlag)
        {
            switch(ulOpertion)
            {
                /* 恢复出厂设置 */
                case CMD_MESH_REST:
                {
                    printf("usr: %s: %d.\r\n",__func__, __LINE__);

                    /* mesh information clear */
                    mesh_info_clear();

                    /* user mesh data clear */
                    #ifdef MESH_USER_DATA_STORE
                    /* 清除mesh用户数据 */
                    app_mesh_user_data_clear();
                    #endif
                    /* 重启 */
                    platform_reset_patch(0);
                    break;  
                }
                /* 启动mesh设置 */
                case CMD_MESH_SETUP:
                {
                    co_printf("[MESH SETUP]\r\n");
                    break;
                }
                default: break;
            }
        }
        lRet = EN_DEV_CTL_RET_CODE_SUCCESSED;
    }
    return lRet;    
}

/**
  * @brief  MeshWrite
  * @note   xxx
  * @param  None
  * @retval None
  */
static long MeshWrite(void *pvHandle, unsigned long ulOpertion, unsigned char *pucDataBuf, unsigned long ulDataLen)
{
    PST_DEV_MANAGE pstDevManage = pvHandle;
    long lRet = EN_DEV_CTL_RET_CODE_FAILED;
    if (0 != pstDevManage)
    {
        PST_Mesh_CTRL pstMeshCtrl = (PST_Mesh_CTRL)pstDevManage->pvData;
        //
        if(true == pstMeshCtrl->bInitFlag)
        {
            switch(ulOpertion)
            {
                /* 发送数据到节点或组 */
                case CMD_MESH_DATA:
                {
                    //uint8_t temp_data[64];
                    uint8_t trans_data[64];
                    uint32_t trans_dataLen = 0;
                    uint8_t param1[32]; uint8_t param2[32];
                    uint32_t param1LEN, param2LEN;
                    uint32_t opcode = 0;
                    /* 获取逗号两边的数据 */
                    cmdGeCommaParameter(pucDataBuf, ulDataLen, param1, &param1LEN, param2, &param2LEN);
                    opcode = str2hex_value(param1, param1LEN);
                    str2hexArr(param2, param2LEN, trans_data);
                    trans_dataLen = param2LEN/2;
                    #if 0
                    printf("[OPCODE:%d]\r\n", opcode);
                    co_printf("\r\n[P1=%s][P2=%s]\r\n", param1, param2);
                    printf("[OPCODE= %d]\r\n", trans_opcode);
                    co_printf("[MESH SENT]\r\n");
                    printf("[MESH RECV UART DATA:\r\n");
                    co_printf("%d, %s", ulDataLen, pucDataBuf);
                    #endif

                    #if 0
                    /* 字符串拼接 */
                    sprintf((char *)trans_data, "%s\r\n",param2);
                    co_printf("[UART-MESH APP: %d, %s]", strlen((char *)trans_data), (char *)trans_data);
                    #else
                    #if 0
                    for(int i = 0; i < trans_dataLen; i ++)
                        printf("%02X ", trans_data[i]);
                    #endif
                    #endif
                    
                    #if 1/* 发布消息 */
                    mesh_publish_msg_t test_publis_msg;
                    test_publis_msg.element_idx = 0;
                    test_publis_msg.model_id = MESH_MODEL_ID_VENDOR_DATA;
                    test_publis_msg.opcode = opcode;
                    test_publis_msg.msg_len = trans_dataLen,
                    memcpy(test_publis_msg.msg, trans_data, test_publis_msg.msg_len);
                    /* 启动发布到app */
                    mesh_publish_msg(&test_publis_msg);
                    #else
                    mesh_rsp_msg_t test_publis_msg;
                    test_publis_msg.element_idx = 0;
                    test_publis_msg.model_id = MESH_MODEL_ID_VENDOR_DATA;
                    test_publis_msg.opcode = opcode;
                    test_publis_msg.msg_len = trans_dataLen,
                    test_publis_msg.dst_addr = 0x002F;
                    memcpy(test_publis_msg.msg, trans_data, test_publis_msg.msg_len);
                    mesh_send_rsp(&test_publis_msg);
                    #endif
                
                    break;
                }
                default: break;
            }
        }
        lRet = EN_DEV_CTL_RET_CODE_SUCCESSED;
    }
    return lRet;
}

/**
  * @brief  MeshControl
  * @note   xxx
  * @param  None
  * @retval None
  */
static long MeshControl (void *pvHandle,unsigned long ulOpertion, unsigned long ulControlCmd, void *pvd)
{
    PST_DEV_MANAGE pstDevManage = pvHandle;
    long lRet = EN_DEV_CTL_RET_CODE_FAILED;
    if (0 != pstDevManage)
    { 
        PST_Mesh_CTRL pstMeshCtrl = (PST_Mesh_CTRL)pstDevManage->pvData;
        /*  */
        if(true == pstMeshCtrl->bInitFlag)
        {
          ;
        }
        lRet = EN_DEV_CTL_RET_CODE_SUCCESSED;
    }
    return lRet;             
}

/**
  * @brief  MeshClose
  * @note   xxx
  * @param  None
  * @retval None
  */
static long MeshClose (void *pvHandle)
{
    PST_DEV_MANAGE pstDevManage = pvHandle;
    long lRet = EN_DEV_CTL_RET_CODE_FAILED;
    if (0 != pstDevManage)
    {
        lRet = EN_DEV_CTL_RET_CODE_SUCCESSED;
    }
    return lRet;     
}



/**
  * @brief  g_stMeshCtlFUN
  * @note  xxx
  * @param  None
  * @retval None
  */
ST_CTR_FUN g_stMeshCtlFUN = 
{
    MeshOpen,		//打开
    MeshRead,		//读
    MeshWrite,		//写
    MeshControl,	//控制
    MeshClose    	//关闭
};


/******************* (C) COPYRIGHT 2011 ShenZhenShiding electronics **************************/
